package dispatcher

///
// 调度库
///
import (
	"time"

	"../log"
)

// Log 全局日志
var Log = log.GetLog("library")

// DisposeParameter 传递参数使用
type DisposeParameter struct {
	Lock  chan int
	Param chan interface{}
}

// Set 传递数据
func (D *DisposeParameter) Set(p interface{}) {
	D.Param <- p
}

// coroutines 协程
type coroutines struct {
	// 执行
	lock *chan *DisposeParameter // 主进程锁
	// 传递
	wait bool // 写参数 (是否有传递参数)
	read bool // 读返回 (函数有返回)
	// 调度
	finish           chan byte             // 结束锁
	target           func(interface{}) int // 处理过程
	DisposeParameter DisposeParameter      // 处理参数
	// 状态
	state bool
}

// handle 协程处理函数
func (d *coroutines) handle() {
	for {
		select {
		case *d.lock <- &d.DisposeParameter: // 开始执行
			// 设置状态
			d.state = true
			// 处理结束
			if d.read {
				//执行处理
				if d.wait {
					d.DisposeParameter.Lock <- d.target(<-d.DisposeParameter.Param)
				} else {
					d.DisposeParameter.Lock <- d.target(nil)
				}
			} else {
				if d.wait {
					d.target(<-d.DisposeParameter.Param)
				} else {
					d.target(nil)
				}
			}
			// 设置状态
			d.state = false
		case <-d.finish: // 结束调度
			return
		}
	}
}

// settarget 设置执行函数
func (d *coroutines) settarget(target func(interface{}) int) {
	d.target = target
}

// Dispatch 调度类
type Dispatch struct {
	lock      chan *DisposeParameter
	min       int                   // 最小数量
	max       int                   // 最大数量
	c         []*coroutines         // 协程列表
	target    func(interface{}) int // 处理函数
	lockawait bool                  // 等待协程结束
	// 传递
	wait bool // 写参数
	read bool // 读返回
	// 调度参数
	scheduling chan bool
}

// Init 设置协程
func (d *Dispatch) Init(min int, max int, wait bool, read bool, target func(interface{}) int) {
	d.min = min
	d.max = max
	d.target = target
	d.wait = wait
	d.read = read
	d.lock = make(chan *DisposeParameter)
	d.scheduling = make(chan bool)
	// 启动协程
	for i := 0; i < min; i++ {
		d.Add()
	}
	// 调度
	go d.Schedulin()
}

// Add 添加协程
func (d *Dispatch) Add() bool {
	// 防止超出最大值
	if len(d.c) < d.max {
		// 创建携程
		d.c = append(d.c, &coroutines{
			lock:   &d.lock,
			read:   d.read,
			wait:   d.wait,
			finish: make(chan byte),
			target: d.target,
			DisposeParameter: DisposeParameter{
				Lock:  make(chan int),
				Param: make(chan interface{}),
			},
		})
		// 启动协程
		go d.c[len(d.c)-1].handle()
		return true
	}
	return false
}

// Remove 删除协程
func (d *Dispatch) Remove() bool {
	// 防止删除过多
	if len(d.c) > d.min {
		// 从队列取出一个
		c := d.c[0]
		d.c = d.c[1:]
		// 设置结束
		c.finish <- 0
		// 设置空
		c = nil
		// 返回
		return true
	}
	return false
}

// Quit 退出全部协程
func (d *Dispatch) Quit() {
	// 设置协程退出
	for i := 0; i < len(d.c); i++ {
		d.c[i].finish <- 0
	}
	// 设置为空
	d.c = nil
}

// Get 获得一个协程处理
func (d *Dispatch) Get() *DisposeParameter {
	select {
	case lock := <-d.lock:
		return lock
	case <-time.After(time.Second * 1): // * 调度超时
		// 启用调度
		d.scheduling <- true
		// 等待新的结果
		return <-d.lock
	}
}

// Schedulin 协程调度
func (d *Dispatch) Schedulin() {
	for {
		// 等待一个调度
		select {
		case <-d.scheduling: // * 新建调度
			// 创建一个协程
			if !d.Add() {
				Log.ErrorS("协程创建失败")
			}
		case <-time.After(time.Second * 10): // * 调度释放
			// 设置调度释放
			d.Remove()
		}
	}
}
